const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const layout = document.getElementById('layout');
const upload = document.getElementById('upload');
const resetUploadBtn = document.getElementById('reset_upload_btn');
const autoHeight = document.getElementById('auto_height');
const packerGroup = document.getElementById('packer_group');
const canvasWidth = document.getElementById('canvas_width');
const canvasHeight = document.getElementById('canvas_height');
const horizontalSpacing = document.getElementById('horizontal_spacing');
const verticalSpacing = document.getElementById('vertical_spacing');
const imgPath = document.getElementById('img_path');
const cssTemplate = document.getElementById('css_template');
const configForm = document.getElementById('config_form');
const downloadCssBtn= document.getElementById('download_css_btn');
const downloadImgBtn = document.getElementById('download_img_btn');

const DEFAULT_CONFIG = {
  //画布大小
  canvas_width: 600,
  canvas_height: 600,
  auto_height: false,
  //packer
  packer_mode: 'optimized',

  //默认间隙 20 像素
  horizontal_spacing: 20,
  vertical_spacing: 20,
  img_path: './images/sprite.png',
  css_template: '.icon_<%=name%>{\n' +
      '  display: inline-block;\n'+
      '  width:<%=w%>px;\n'+
      '  height:<%=h%>px;\n'+
      '  background-image:url(<%=path%>);\n' +
      '  background-position: -<%=x%>px -<%=y%>px;\n' +
      '  background-repeat: no-repeat;\n}'
};
//初始化数据渲染
canvas.width = DEFAULT_CONFIG.canvas_width;
canvas.height = DEFAULT_CONFIG.canvas_height;
canvasWidth.placeholder = DEFAULT_CONFIG.canvas_width;
canvasHeight.placeholder = DEFAULT_CONFIG.canvas_height;
horizontalSpacing.placeholder = DEFAULT_CONFIG.horizontal_spacing;
verticalSpacing.placeholder = DEFAULT_CONFIG.vertical_spacing;
imgPath.value = DEFAULT_CONFIG.img_path;
cssTemplate.value = DEFAULT_CONFIG.css_template;

//全局变量
//图片集合
let imgObjects = [];
//布局
let packer = null;
//自定义内容
let customize = {};

upload.addEventListener('change', () => {
  const files = upload.files;
  handleUpload(files);
});
//拖拽上传
layout.addEventListener('drop', function(ev) {
  ev.preventDefault();
  const files = ev.dataTransfer.files;
  handleUpload(files);
}, false);

document.addEventListener('dragover', function(event) {
  event.preventDefault();
});

//清空已上传
resetUploadBtn.addEventListener('click', () => {
  resetUpload();
});

//自适应canvas高度
autoHeight.addEventListener('click', function() {
  canvasHeight.disabled = !!this.checked;
});

//布局按钮组
packerGroup.addEventListener('click', (e) => {
  const btn = e.target;
  packerGroup.querySelectorAll('[data-packer]').forEach(el => {
    el.classList.remove('active');
  });
  btn.classList.add('active');
  switch (btn.dataset.packer) {
    case 'ordered':
      customize.packer_mode = 'ordered';
      break;
    case 'optimized':
      customize.packer_mode = 'optimized';
      break;
    case 'vertical':
      customize.packer_mode = 'vertical';
      break;
    case 'horizontal':
      customize.packer_mode = 'horizontal';
      break;
    default:
      break;
  }
  canvasDraw(canvas,imgObjects,customize);
});

configForm.addEventListener('submit', function(e) {
  e.preventDefault();
  const formData = new FormData(this);
  const canvas_width = formData.get('canvas_width');
  const canvas_height = formData.get('canvas_height');
  const auto_height = formData.get('auto_height');
  const vertical_spacing = formData.get('vertical_spacing');
  const horizontal_spacing = formData.get('horizontal_spacing');
  const scaling_ratio = formData.get('scaling_ratio');
  const img_path = formData.get('img_path');
  const css_template = formData.get('css_template');
  if(canvas_width){
    customize.canvas_width = parseInt(canvas_width);
  }
  if(canvas_height){
    customize.canvas_height = parseInt(canvas_height);
  }
  if(auto_height){
    customize.auto_height = auto_height;
  }
  if(vertical_spacing){
    customize.vertical_spacing = parseInt(vertical_spacing);
  }
  if(horizontal_spacing){
    customize.horizontal_spacing = parseInt(horizontal_spacing);
  }
  if(scaling_ratio){
    customize.scaling_ratio = parseFloat(scaling_ratio);
  }
  if(img_path){
    customize.img_path = img_path;
  }
  if(css_template){
    customize.css_template = css_template;
  }
  canvasDraw(canvas,imgObjects,customize);
});
downloadCssBtn.onclick = downloadCss;
downloadImgBtn.onclick = downloadImg;
/**
 *
 * @param canvas
 * @param {Array} imgObjects
 * @param {Object} customize 自定义配置
 */
const canvasDraw = function(canvas, imgObjects, customize) {
  if(imgObjects.length === 0){
    return false;
  }
  const ctx = canvas.getContext('2d');
  packer = new Packer(imgObjects, Object.assign({}, DEFAULT_CONFIG, customize));
  const temp = packer.posCalc();
  switch (packer.config.packer_mode) {
    case 'ordered':
    case 'optimized':
      if (packer.config.auto_height) {
        canvas.width = temp.fit.w;
        canvas.height = temp.fit.h;
      } else {
        canvas.width = packer.config.canvas_width;
        canvas.height = packer.config.canvas_height;
      }
      break;
    case 'vertical':
    case 'horizontal':
      canvas.width = temp.fit.w;
      canvas.height = temp.fit.h;
      break;
    default:
      break;
  }
  temp && temp.imgArr.forEach(img => {
    ctx.drawImage(img.el, img.x, img.y, img.w, img.h);
  });
  return Object.assign({},temp,{config: packer.config});
};

//文件上传处理
function handleUpload(files) {
  fileHandler(files).then((arr) => {
    canvasDraw(canvas,arr,customize);
  });
}

//将文件转化为imgObjects
/***
 *
 * @param files
 * @returns {Promise}
 */
function fileHandler(files) {
  let numbers = files.length;
  return new Promise(((resolve) => {
    Array.from(files).forEach((val) => {
      const name = val.name;
      const type = val.type;
      if (val.type.indexOf('image') === 0) {
        let reader = new FileReader();
        reader.readAsDataURL(val);
        reader.onload = e => {
          const dataURL = e.target.result;
          const imgEl = new Image();
          imgEl.src = dataURL;

          imgEl.onload = () => {
            const w = parseInt(imgEl.width);
            const h = parseInt(imgEl.height);
            imgObjects.push({
              el: imgEl,
              w: w,
              h: h,
              x: 0,
              y: 0,
              name: name,
              type: type,
              base64: dataURL
            });
            --numbers;
            if (numbers === 0) {
              resolve(imgObjects);
            }
          };
        };
      }
      else {
        const err = new Error(name + ' is not an image!');
        alert(err);
        --numbers;
        if (numbers === 0) {
          resolve(imgObjects);
        }
      }

    });
  }));
}

/**
 * @param {Array} imgObjects 传入的图片数组
 * @param {Object} config
 */
class Packer {
  constructor(imgObjects, config) {
    if (!(imgObjects instanceof Array)) {
      return;
    }
    //为了不影响原始数据
    this.imgObjects = [...imgObjects];
    this.config = config;
  }

  init() {
    this.pointer = {
      y: 0, //当前行的坐标
      w: 0, //当前行已使用的宽度
      h: 0 //当前行已使用的高度
    };
  }

  _sort() {
    return Array.from(this.imgObjects).sort(function(a, b) {
      if (b.h - a.h !== 0) {
        return b.h - a.h;
      } else {
        return a.w - b.w;
      }
    });
  }
  posCalc(){
    this.init();
    switch (this.config.packer_mode){
      case 'optimized':
        return this._posCalc(this._sort());
      case 'ordered':
      case 'vertical':
      case 'horizontal':
        return this._posCalc(this.imgObjects);
      default:
        break;
    }
  }

  _posCalc(arr) {
    const temp = Array.from(arr);
    let fitW = 0;
    let fitH = 0;
    if (this.config.packer_mode === 'horizontal') {
      temp.forEach(img => {
        img.x = this.pointer.w;
        img.y = this.pointer.y;
        this.pointer.w =this.config.horizontal_spacing + this.pointer.w + img.w;
        this.pointer.h = Math.max(this.pointer.h, img.h);
      });
      fitW = this.pointer.w - this.config.horizontal_spacing;
      fitH = this.pointer.h;
    } else if (this.config.packer_mode === 'vertical') {
      temp.forEach(img => {
        fitW = Math.max(img.w, fitW);
        img.x = this.pointer.w;
        img.y = this.pointer.y;
        this.pointer.h = this.config.vertical_spacing + img.h;
        this.pointer.y = this.pointer.y + this.pointer.h;
      });
      fitH = this.pointer.y - this.config.vertical_spacing;
      console.log(this.imgObjects);
    } else {
      temp.forEach((img) => {
        //判断是否换行
        if (this.pointer.w + img.w > this.config.canvas_width) {
          //换行了
          this.pointer.y = this.pointer.y + this.pointer.h;
          this.pointer.w = 0;
          this.pointer.h = 0;
        }
        img.x = this.pointer.w;
        img.y = this.pointer.y;
        this.pointer.w = this.pointer.w + img.w +
            this.config.horizontal_spacing;
        this.pointer.h = Math.max(this.pointer.h, img.h +
            this.config.vertical_spacing);
      });
      fitW = this.config.canvas_width;
      fitH = this.pointer.y + this.pointer.h - this.config.vertical_spacing;
    }

    const fit = {
      w: fitW,
      h: fitH
    };
    return {
      imgArr: temp,
      fit: fit
    };
  }
}


const clear = function() {
  context.clearRect(0, 0, canvas.width, canvas.height);
};
//清空已上传
const resetUpload = function() {
  imgObjects = [];
  clear();
  packer = null;
};

function downloadCss() {
  downloadFile(makeCss(),'text/plain','style.css');
}
function downloadImg() {
  const dataUrl = canvas.toDataURL();
  const a = document.createElement('a');
  a.download = 'icon.png';
  a.href = dataUrl;
  a.click();
}
function makeCss() {
  const draw = canvasDraw(canvas,imgObjects,customize);
  if(!draw) return;
  let cache = [];
  draw.imgArr.map((o) => {
    const t = tmpRender(draw.config.css_template,{
      w: o.w,
      h: o.h,
      x: o.x,
      y: o.y,
      name: o.name.split('.')[0],
      path: draw.config.img_path
    });
    cache.push(t);
  });
  return cache.join('\n');
}

function downloadFile(file,MIME_TYPE,fileName) {
  const blob = new Blob([file],{type: MIME_TYPE});
  const a = document.createElement('a');
  a.download = fileName || 'demo.txt';
  a.href = window.URL.createObjectURL(blob);
  a.click();
}
/**
 *
 * @param {String} template
 * @param {Object} data
 */
function tmpRender(template, data) {
  if(typeof data !== 'object') return;
  const re = /<%=([^%>]+)?%>/g;
  // eslint-disable-next-line no-cond-assign
  // while(match = re.exec(template)) {
  //个别地方无法匹配全
  //   template = template.replace(match[0], data[match[1]]);
  // }
  return template.replace(re,function(s) {
    const temp = s.split('<%=')[1].split('%>')[0];
    return data[temp];
  });
}

//todo 图片缩放